package com.techsoul.module.system.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.techsoul.common.core.exception.BaseException;
import com.techsoul.common.core.exception.ParamException;
import com.techsoul.common.core.pojo.vo.MenuVo;
import com.techsoul.common.core.pojo.vo.OrgVo;
import com.techsoul.common.core.pojo.vo.UserVo;
import com.techsoul.common.core.util.ServletUtils;
import com.techsoul.common.core.util.bean.BeanUtils;
import com.techsoul.common.core.util.collection.ListUtils;
import com.techsoul.common.core.util.id.IdWorker;
import com.techsoul.common.security.annotation.DataScope;
import com.techsoul.common.security.service.TokenService;
import com.techsoul.module.system.mapper.RoleMapper;
import com.techsoul.module.system.pojo.entity.Role;
import com.techsoul.module.system.pojo.param.RoleMenuRelSaveParam;
import com.techsoul.module.system.pojo.param.RoleOrgRelSaveParam;
import com.techsoul.module.system.pojo.param.RoleSaveParam;
import com.techsoul.module.system.pojo.param.RoleSearchParam;
import com.techsoul.common.core.pojo.vo.RoleVo;
import com.techsoul.module.system.service.*;
import com.techsoul.module.system.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色 Service实现
 * 
 * @author liuen
 * @date 2020-12-04
 */
@Service
@Transactional(readOnly = true)
public class RoleServiceImpl implements IRoleService {

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RoleMapper mapper;

    @Autowired
    private IOrgService sysOrgService;

    @Autowired
    private IMenuService menuService;

    @Autowired
    private IRoleOrgRelService sysRoleOrgRelService;

    @Autowired
    private IRoleMenuRelService sysRoleMenuRelService;

    @Autowired
    private TokenService tokenService;

    /**
     * 新增
     * @param params
     * @return
     */
    @Transactional(readOnly = false)
    @Override
    public String insert(RoleSaveParam params) {
        UserVo user = tokenService.getLoginUser(ServletUtils.getRequest()).getUser();
        // 新增角色
        Role entity = new Role();
        BeanUtils.copyProperties(params, entity);
        entity.setId(idWorker.nextId() + "").preInsert(user.getId());
        this.mapper.insert(entity);
        // 新增角色菜单
        if (ListUtils.isNotEmpty(params.getMenuIds())) {
            params.getMenuIds().forEach(menuId -> {
                RoleMenuRelSaveParam roleMenuRelSaveParam = new RoleMenuRelSaveParam();
                roleMenuRelSaveParam.setRoleId(entity.getId())
                        .setMenuId(menuId);
                sysRoleMenuRelService.insert(roleMenuRelSaveParam);
            });
        }
        return entity.getId();
    }

    /**
     * 删除
     * @param id
     * @return
     */
    @Transactional(readOnly = false)
    @Override
    public Integer delete(String id) {
        this.checkRoleAllowed(id);
        return this.mapper.deleteById(id);
    }

    /**
     * 批量删除
     * @param idList
     */
    @Transactional(readOnly = false)
    @Override
    public Integer batchDelete(List<String> idList) {
        if (ListUtils.isNotEmpty(idList)) {
            idList.forEach(id -> this.checkRoleAllowed(id));
            return this.mapper.deleteBatchIds(idList);
        } else {
            return 0;
        }
    }

    /**
     * 修改
     * @param params
     * @return
     */
    @Transactional(readOnly = false)
    @Override
    public Integer update(RoleSaveParam params) {
        Role entityFromDb = this.mapper.selectById(params.getId());
        if (entityFromDb == null) {
            throw new ParamException("id=" + params.getId());
        }
        UserVo user = tokenService.getLoginUser(ServletUtils.getRequest()).getUser();
//        this.checkRoleAllowed(params.getId());
        BeanUtils.copyProperties(params, entityFromDb);
        entityFromDb.preUpdate(user.getId());
        return this.mapper.updateById(entityFromDb);
    }

    /**
     * 修改角色菜单
     * @param params
     * @return
     */
    @Transactional(readOnly = false)
    @Override
    public void updateRoleMenus(RoleSaveParam params) {
        // 更新角色
        this.update(params);
        // 更新角色菜单，全删全入
        sysRoleMenuRelService.deleteByRoleId(params.getId());
        if (ListUtils.isNotEmpty(params.getMenuIds())) {
            params.getMenuIds().forEach(menuId -> {
                RoleMenuRelSaveParam roleMenuRelSaveParam = new RoleMenuRelSaveParam();
                roleMenuRelSaveParam.setRoleId(params.getId())
                        .setMenuId(menuId);
                sysRoleMenuRelService.insert(roleMenuRelSaveParam);
            });
        }
    }

    /**
     * 修改数据权限
     * @param params
     * @return
     */
    @Transactional(readOnly = false)
    @Override
    public void updateDataScope(RoleSaveParam params) {
        // 更新角色
        this.update(params);
        // 更新角色组织，全删全入
        sysRoleOrgRelService.deleteByRoleId(params.getId());
        if (ListUtils.isNotEmpty(params.getOrgIds())) {
            params.getOrgIds().forEach(orgId -> {
                RoleOrgRelSaveParam roleOrgRelSaveParam = new RoleOrgRelSaveParam();
                roleOrgRelSaveParam.setRoleId(params.getId())
                        .setOrgId(orgId);
                sysRoleOrgRelService.insert(roleOrgRelSaveParam);
            });
        }
    }

    /**
     * 详情
     * @param id
     * @return
     */
    @Override
    public RoleVo findById(String id) {
        RoleVo roleVo = this.mapper.findById(id);
        List<OrgVo> roleOrgs = sysOrgService.findRoleOrgs(roleVo.getId());
        List<MenuVo> roleMenus = menuService.findRoleMenus(roleVo.getId());
        roleVo.setRoleOrgs(roleOrgs)
                .setRoleMenus(roleMenus);
        return roleVo;
    }

    /**
     * 列表
     * @param params
     * @return
     */
    @DataScope(userAlias = "t2", orgAlias = "t3")
    @Override
    public List<RoleVo> findAll(RoleSearchParam params) {
        this.genSort(params);
        return this.mapper.findAll(params);
    }

    /**
     * 列表-分页
     * @param params
     * @param current
     * @param pageSize
     * @return
     */
    @DataScope(userAlias = "t2", orgAlias = "t3")
    @Override
    public IPage<RoleVo> findAll(RoleSearchParam params, Integer current, Integer pageSize) {
        this.genSort(params);
        return this.mapper.findAll(new Page<>(current, pageSize), params);
    }

    /**
     * 列表-可选项
     * @return
     */
    @Override
    public List<RoleVo> findOptions() {
//        List<RoleVo> roleVos = this.findAll(new RoleSearchParam());
//        String userId = tokenService.getLoginUser(ServletUtils.getRequest()).getUser().getId();
//        return UserVo.isAdmin(userId) ? roleVos : roleVos.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList());
        return this.findAll(new RoleSearchParam());
    }

    /**
     * 列表-用户角色
     * @return
     */
    @Override
    public List<RoleVo> findUserRoles() {
        String userId = tokenService.getLoginUser(ServletUtils.getRequest()).getUser().getId();
        return this.mapper.findUserRoles(userId);
    }

    /**
     * 列表-用户角色
     * @param userId
     * @return
     */
    @Override
    public List<RoleVo> findUserRoles(String userId) {
        return this.mapper.findUserRoles(userId);
    }

    /**
     * 校验角色是否允许操作
     * @param id
     */
    @Override
    public void checkRoleAllowed(String id) {
        UserVo user = tokenService.getLoginUser(ServletUtils.getRequest()).getUser();
        if (!user.isAdmin() && StringUtils.isNotBlank(id) && RoleVo.isAdmin(id)) {
            throw new BaseException("不允许操作超级管理员角色");
        }
    }

    /**
     * 生成排序信息
     * @param params
     */
    private void genSort(RoleSearchParam params) {
        if (StringUtils.isNotBlank(params.getSortProperty())) {
            if ("roleCode".equals(params.getSortProperty())) {
                params.setSortColumn("t1.role_code");
            }
            if ("roleName".equals(params.getSortProperty())) {
                params.setSortColumn("t1.role_name");
            }
        } else {
            params.setSortColumn("t1.create_time");
            params.setSortDirection("desc");
        }
    }

}
